﻿Imports System.Collections.ObjectModel
Imports System.Reflection
Imports Kairyu.DCEngine
Imports System.Collections.Specialized


''' <summary>
''' 読み込み可能リストアクティベータ
''' </summary>
''' <remarks>
''' </remarks>
Public Class LoadableListActivator

    ''' <summary>
    ''' 生成します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Activate(current As Object, lowerProperty As PropertyInfo) As ILoadableList
        If current Is Nothing Then Throw New ArgumentNullException("current")
        If lowerProperty Is Nothing Then Throw New ArgumentNullException("lowerProperty")

        Dim c As New LoadableListActivator(current, lowerProperty)
        Return c.ActivateLoadableList
    End Function

    ''' <summary>
    ''' 生成します
    ''' </summary>
    ''' <param name="loader"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Activate(current As Object, lowerProperty As PropertyInfo, loader As Loader) As ILoadableList
        If current Is Nothing Then Throw New ArgumentNullException("current")
        If lowerProperty Is Nothing Then Throw New ArgumentNullException("lowerProperty")
        If loader Is Nothing Then Throw New ArgumentNullException("loader")

        Dim c As New LoadableListActivator(current, lowerProperty)
        Dim lst = c.ActivateLoadableList

        '検索条件作成
        Dim provider = New FetchQueryProvider(loader, lst)

        Dim qt As Type = c.LowerT.ToQueryGenericType
        Dim query As IQuery = Activator.CreateInstance(qt, provider)

        '親プロパティは結合条件から外す
        query.IgnoreJoins.Add(c.ParentProperty)

        Dim lower = Activator.CreateInstance(c.LowerT)
        c.ParentProperty.SetValue(lower, current, Nothing)
        Dim condition = InstanceCondition.Create(lower, c.ParentProperty.ToLiteralProperties.ToList)
        query.Conditions.Add(condition)

        '検索条件追加
        lst.SetQuery(query)

        Return lst
    End Function

    ''' <summary>
    ''' コンストラクタ
    ''' </summary>
    ''' <param name="current">自身のインスタンス</param>
    ''' <param name="lowerProperty">下層プロパティ</param>
    ''' <remarks></remarks>
    Private Sub New(current As Object, lowerProperty As PropertyInfo)
        Me.Current = current
        Me.LowerT = lowerProperty.PropertyType.GetGenericArguments.First

        Dim parents = (From el In Me.LowerT.GetProperties Where el.IsKey AndAlso el.PropertyType.Equals(current.GetType)).ToList
        If parents.Count <> 1 Then Throw New InvalidOperationException
        Me.ParentProperty = parents.First
    End Sub

    ''' <summary>
    ''' 起点オブジェクト
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Property Current As Object

    ''' <summary>
    ''' 下層プロパティの型
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Property LowerT As Type

    ''' <summary>
    ''' 下層から見た親プロパティ
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Property ParentProperty As PropertyInfo

    ''' <summary>
    ''' 読み込み可能リストを生成します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function ActivateLoadableList() As ILoadableList
        Dim collectionT = Me.LowerT.ToLoadableListGenericType
        Dim lst = Activator.CreateInstance(collectionT, {Me.Current, Me.ParentProperty})

        Return lst
    End Function


End Class
